﻿using System;
using System.IO.Ports;
using System.Text;

/// <summary>
/// https://code.msdn.microsoft.com/windowsdesktop/SerialPort-brief-Example-ac0d5004
/// </summary>
namespace serialport
{
    /// <summary>
    /// Base class for serialport. Interfaces with a serial port. There should only be one 
    /// instance of this class for each serial port to be used.
    /// </summary>
    public class SerialPortBase
    {
        protected SerialPort serialport_ = new SerialPort();
        protected int baudrate_ = 115200;
        protected int data_bits_ = 8;
        protected Handshake handshake_ = Handshake.None;
        protected Parity parity_ = Parity.None;
        protected string port_name_ = "COM1";
        protected StopBits stop_bits_ = StopBits.One;

        public int BaudRate { get { return baudrate_; } set { baudrate_ = value; } }
        public int DataBits { get { return data_bits_; } set { data_bits_ = value; } }
        public Handshake Handshake { get { return handshake_; } set { handshake_ = value; } }
        public Parity Parity { get { return parity_; } set { parity_ = value; } }
        public string PortName { get { return port_name_; } set { port_name_ = value; } }

        public virtual bool open()
        {
            try
            {
                serialport_.BaudRate = baudrate_;
                serialport_.DataBits = data_bits_;
                serialport_.Handshake = handshake_;
                serialport_.Parity = parity_;
                serialport_.PortName = port_name_;
                serialport_.StopBits = stop_bits_;
                serialport_.Open();
            }
            catch { return false; }
            return true;
        }

        public virtual void close() {
            serialport_.Close();
            serialport_ = null;
        }
    }

    /// <summary>
    /// 该串口类支持自定义接收结束符号。
    /// </summary>
    public class SerialPortHandle : SerialPortBase
    {
        /// <summary>
        /// Holds data received until we get a terminator.
        /// </summary>
        private string recv_buf_ = string.Empty;
        private string recv_str_ = string.Empty;
        /// <summary>
        /// End of transmition byte in this case EOT (ASCII 4).
        /// </summary>
        private byte terminator_ = 0x4;

        public byte Terminator { get { return terminator_; } set { terminator_ = value; } }
        public override bool open()
        {
            if (!base.open())
            {
                return false;
            }
            base.serialport_.DataReceived += new SerialDataReceivedEventHandler(dataReceivedHandler);
            return true;
        }

        public string read() { return recv_str_; }
        public void write(string data) { base.serialport_.Write(data); }

        private void dataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
        {
            //Initialize a buffer to hold the received data
            byte[] buffer = new byte[base.serialport_.ReadBufferSize];

            //There is no accurate method for checking how many bytes are read
            //unless you check the return from the Read method
            int bytesRead = serialport_.Read(buffer, 0, buffer.Length);

            //For the example assume the data we are received is ASCII data.
            recv_buf_ += Encoding.ASCII.GetString(buffer, 0, bytesRead);
            //Check if string contains the terminator
            if (recv_buf_.IndexOf((char)terminator_) > -1)
            {
                //If tString does contain terminator we cannot assume that it is the last character received
                recv_str_ = recv_buf_.Substring(0, recv_buf_.IndexOf((char)terminator_));
                //Remove the data up to the terminator from tString
                recv_buf_ = recv_buf_.Substring(recv_buf_.IndexOf((char)terminator_));
            }
        }
    }

    /// <summary>
    /// 该串口类的接收结束符号为 '\r\n' 类。
    /// </summary>
    public class SerialPortNor : SerialPortBase
    {
        public string readLine()
        {
            return serialport_.ReadLine();
        }
        public void write(string data)
        {
            serialport_.Write(data);
        }
    }

    /// <summary>
    /// 这里定义了两个串口模块，一个的接收结束符是'\r\n'，另外一个支持自定义接收结束符。
    /// </summary>
	class MainClass
	{
        public static void Main(string[] args)
        {
            /*******Test for SerialPortHandle.******/
            // 支持自定义接收结束符号
            SerialPortHandle serial1 = new SerialPortHandle();
            serial1.PortName = "COM3";
            serial1.BaudRate = 115200;
            serial1.Terminator = (byte)'*';
            serial1.open();

            serial1.write("123456\r\n7*89");
            System.Threading.Thread.Sleep(500);
            System.Console.WriteLine(serial1.read());   // Out==> 123456\r\n7
            serial1.close();

            /********Test for SerialPortNor ******/
            // 以'\r\n'为接收结束符号
            SerialPortNor serial2 = new SerialPortNor();
            serial2.PortName = "COM3";
            serial2.BaudRate = 115200;
            serial2.open();
            serial2.write("123456\r\n");
            System.Console.WriteLine( serial2.readLine());  // Out ==> 123456

            System.Console.ReadKey();
        }
	}
}
